import * as extentExports from "ol/extent";
import WMTSTileGrid from "ol/tilegrid/WMTS";
import * as Projection from "ol/proj";
import * as Layer from "ol/layer";
import { TDTLayerType } from "./types";
import * as Source from "ol/source";
import * as keys from "./keys";
import { getMap } from "./instance";

const TDT_KEY = "5dae8bc94205662e7f5a622c2b1c9968";
const TDT_LAYER_SERVICE_BASE_URL = "http://t{0-7}.tianditu.gov.cn";

const projection = Projection.get("EPSG:4326") as Projection.Projection;
const projectionExtent = projection.getExtent();
const size = extentExports.getWidth(projectionExtent) / 256;
const resolutions = new Array(19);
const matrixIds = new Array(19);
for (let z = 1; z < 19; ++z) {
  // generate resolutions and matrixIds arrays for this WMTS
  resolutions[z] = size / Math.pow(2, z);
  matrixIds[z] = z;
}
// 瓦片网格
export const _tileGrid = new WMTSTileGrid({
  origin: extentExports.getTopLeft(projectionExtent),
  resolutions,
  matrixIds,
});

/**
 * @description: 创建天地图全部图层
 * @param {object} options 配置项
 * @param {TDTLayerType} options.defaultLayer 默认展示的图层
 * @param {boolean} options.mark 是否显示标注
 * @returns {Array<Layer.Tile<Source.WMTS>>}
 */
export const createTDTAllLayers = (
  options: { defaultLayer?: TDTLayerType; mark?: boolean } = {}
): Array<Layer.Tile<Source.WMTS>> => {
  const { defaultLayer, mark } = options ?? {};

  return [
    ...createTDTSatelliteLayers({
      visible: defaultLayer === "satellite",
      mark: defaultLayer === "satellite" ? mark : false,
    }),
    ...createTDTVectorLayers({
      visible: defaultLayer === "vector",
      mark: defaultLayer === "vector" ? mark : false,
    }),
    ...createTDTDarkVectorLayers({
      visible: defaultLayer === "dark-vector",
      mark: defaultLayer === "dark-vector" ? mark : false,
    }),
  ];
};
/**
 * @description: 创建天地图影像图层
 * @param {Object} options 配置项
 * @param {boolean} options.visible 是否可见
 * @param {boolean} options.mark 是否显示标记
 * @returns {Array<Layer.Tile<Source.WMTS>>}
 */
export const createTDTSatelliteLayers = (
  options: { visible?: boolean; mark?: boolean } = {}
): Array<Layer.Tile<Source.WMTS>> => {
  const { visible = true, mark = true } = options;
  const projection = Projection.get("EPSG:4326") as Projection.Projection;
  const projectionExtent = projection.getExtent();
  const size = extentExports.getWidth(projectionExtent) / 256;
  const resolutions = new Array(19);
  const matrixIds = new Array(19);
  for (let z = 1; z < 19; ++z) {
    // generate resolutions and matrixIds arrays for this WMTS
    resolutions[z] = size / Math.pow(2, z);
    matrixIds[z] = z;
  }

  const defaultLayer = new Layer.Tile({
    source: new Source.WMTS({
      attributions: `Tiles © <a href="http://www.tianditu.com/service/info.html?sid=5292&type=info">${"天地图"}</a>`,
      crossOrigin: "anonymous",
      url: `${TDT_LAYER_SERVICE_BASE_URL}/img_c/wmts?tk=${TDT_KEY}`,
      layer: "img",
      matrixSet: "c",
      format: "tiles",
      projection,
      tileGrid: new WMTSTileGrid({
        origin: extentExports.getTopLeft(projectionExtent),
        resolutions,
        matrixIds,
      }),
      style: "default",
      wrapX: true,
    }),
    visible,
  });
  defaultLayer.set(keys.LAYER_TYPE_KEY, "satellite");
  defaultLayer.set(keys.LAYER_NAME_KEY, "default");
  defaultLayer.set(keys.LAYER_SOURCE_KEY, "tianditu");
  defaultLayer.set(keys.LAYER_FORMAT_KEY, "wmts");

  const markerLayer = new Layer.Tile({
    source: new Source.WMTS({
      attributions: `Tiles © <a href="http://www.tianditu.com/service/info.html?sid=5292&type=info">${"天地图"}</a>`,
      crossOrigin: "anonymous",
      url: `${TDT_LAYER_SERVICE_BASE_URL}/cia_c/wmts?tk=${TDT_KEY}`,
      layer: "cia",
      matrixSet: "c",
      format: "tiles",
      projection,
      tileGrid: new WMTSTileGrid({
        origin: extentExports.getTopLeft(projectionExtent),
        resolutions,
        matrixIds,
      }),
      style: "default",
      wrapX: true,
    }),
    visible: visible ? mark : visible,
  });
  markerLayer.set(keys.LAYER_TYPE_KEY, "satellite");
  markerLayer.set(keys.LAYER_NAME_KEY, "marker");
  markerLayer.set(keys.LAYER_SOURCE_KEY, "tianditu");
  markerLayer.set(keys.LAYER_FORMAT_KEY, "wmts");

  const borderLayer = new Layer.Tile({
    source: new Source.WMTS({
      attributions: `Tiles © <a href="http://www.tianditu.com/service/info.html?sid=5292&type=info">${"天地图"}</a>`,
      crossOrigin: "anonymous",
      url: `${TDT_LAYER_SERVICE_BASE_URL}/ibo_c/wmts?tk=${TDT_KEY}`,
      layer: "ibo",
      matrixSet: "c",
      format: "tiles",
      projection,
      tileGrid: new WMTSTileGrid({
        origin: extentExports.getTopLeft(projectionExtent),
        resolutions,
        matrixIds,
      }),
      style: "default",
      wrapX: true,
    }),
    visible: visible ? mark : visible,
  });
  // borderLayer.set(keys.LAYER_TYPE_KEY, 'satellite')
  // borderLayer.set(keys.LAYER_NAME_KEY, 'border')
  // borderLayer.set(keys.LAYER_SOURCE_KEY, 'tianditu')
  // borderLayer.set(keys.LAYER_FORMAT_KEY, 'wmts')

  return [defaultLayer, markerLayer, borderLayer];
};
/**
 * @description: 创建天地图矢量图层
 * @param {Object} options 配置项
 * @param {boolean} options.visible 是否可见
 * @param {boolean} options.mark 是否显示标记
 * @returns {Array<Layer.Tile<Source.WMTS>>}
 */
export const createTDTVectorLayers = (
  options: { visible?: boolean; mark?: boolean } = {}
): Array<Layer.Tile<Source.WMTS>> => {
  const { visible = true, mark = true } = options;

  const defaultLayer = new Layer.Tile({
    source: new Source.WMTS({
      attributions: `Tiles © <a href="http://www.tianditu.com/service/info.html?sid=5292&type=info">${"天地图"}</a>`,
      crossOrigin: "anonymous",
      url: `${TDT_LAYER_SERVICE_BASE_URL}/vec_c/wmts?tk=${TDT_KEY}`,
      layer: "vec",
      matrixSet: "c",
      format: "tiles",
      projection,
      tileGrid: _tileGrid,
      style: "default",
      wrapX: true,
    }),
    visible,
  });
  defaultLayer.set(keys.LAYER_TYPE_KEY, "vector");
  defaultLayer.set(keys.LAYER_NAME_KEY, "default");
  defaultLayer.set(keys.LAYER_SOURCE_KEY, "tianditu");
  defaultLayer.set(keys.LAYER_FORMAT_KEY, "wmts");

  const markerLayer = new Layer.Tile({
    source: new Source.WMTS({
      attributions: `Tiles © <a href="http://www.tianditu.com/service/info.html?sid=5292&type=info">${"天地图"}</a>`,
      crossOrigin: "anonymous",
      url: `${TDT_LAYER_SERVICE_BASE_URL}/cva_c/wmts?tk=${TDT_KEY}`,
      layer: "cva",
      matrixSet: "c",
      format: "tiles",
      projection,
      tileGrid: _tileGrid,
      style: "default",
      wrapX: true,
    }),
    visible: visible ? mark : visible,
  });
  markerLayer.set(keys.LAYER_TYPE_KEY, "vector");
  markerLayer.set(keys.LAYER_NAME_KEY, "marker");
  markerLayer.set(keys.LAYER_SOURCE_KEY, "tianditu");
  markerLayer.set(keys.LAYER_FORMAT_KEY, "wmts");

  const borderLayer = new Layer.Tile({
    source: new Source.WMTS({
      attributions: `Tiles © <a href="http://www.tianditu.com/service/info.html?sid=5292&type=info">${"天地图"}</a>`,
      crossOrigin: "anonymous",
      url: `${TDT_LAYER_SERVICE_BASE_URL}/ibo_c/wmts?tk=${TDT_KEY}`,
      layer: "ibo",
      matrixSet: "c",
      format: "tiles",
      projection,
      tileGrid: _tileGrid,
      style: "default",
      wrapX: true,
    }),
    visible: visible ? mark : visible,
  });
  borderLayer.set(keys.LAYER_TYPE_KEY, "vector");
  borderLayer.set(keys.LAYER_NAME_KEY, "border");
  borderLayer.set(keys.LAYER_SOURCE_KEY, "tianditu");
  borderLayer.set(keys.LAYER_FORMAT_KEY, "wmts");

  return [defaultLayer, markerLayer, borderLayer];
};
/**
 * @description: 创建天地图矢量图层
 * @param {Object} options 配置项
 * @param {boolean} options.visible 是否可见
 * @param {boolean} options.mark 是否显示标记
 * @returns {Array<Layer.Tile<Source.WMTS>>}
 */
export const createTDTDarkVectorLayers = (
  options: { visible?: boolean; mark?: boolean } = {}
): Array<Layer.Tile<Source.WMTS>> => {
  const { visible = true, mark = true } = options;

  const defaultLayer = new Layer.Tile({
    className: "ol-layer-tianditu-vector--dark",
    source: new Source.WMTS({
      attributions: `Tiles © <a href="http://www.tianditu.com/service/info.html?sid=5292&type=info">${"天地图"}</a>`,
      crossOrigin: "anonymous",
      url: `${TDT_LAYER_SERVICE_BASE_URL}/vec_c/wmts?tk=${TDT_KEY}`,
      layer: "vec",
      matrixSet: "c",
      format: "tiles",
      projection,
      tileGrid: _tileGrid,
      style: "default",
      wrapX: true,
    }),
    visible,
  });
  defaultLayer.set(keys.LAYER_TYPE_KEY, "dark-vector");
  defaultLayer.set(keys.LAYER_NAME_KEY, "default");
  defaultLayer.set(keys.LAYER_SOURCE_KEY, "tianditu");
  defaultLayer.set(keys.LAYER_FORMAT_KEY, "wmts");

  const markerLayer = new Layer.Tile({
    className: "ol-layer-tianditu-vector--dark",
    source: new Source.WMTS({
      attributions: `Tiles © <a href="http://www.tianditu.com/service/info.html?sid=5292&type=info">${"天地图"}</a>`,
      crossOrigin: "anonymous",
      url: `${TDT_LAYER_SERVICE_BASE_URL}/cva_c/wmts?tk=${TDT_KEY}`,
      layer: "cva",
      matrixSet: "c",
      format: "tiles",
      projection,
      tileGrid: _tileGrid,
      style: "default",
      wrapX: true,
    }),
    visible: visible ? mark : visible,
  });
  markerLayer.set(keys.LAYER_TYPE_KEY, "dark-vector");
  markerLayer.set(keys.LAYER_NAME_KEY, "marker");
  markerLayer.set(keys.LAYER_SOURCE_KEY, "tianditu");
  markerLayer.set(keys.LAYER_FORMAT_KEY, "wmts");

  const borderLayer = new Layer.Tile({
    className: "ol-layer-tianditu-vector--dark",
    source: new Source.WMTS({
      attributions: `Tiles © <a href="http://www.tianditu.com/service/info.html?sid=5292&type=info">${"天地图"}</a>`,
      crossOrigin: "anonymous",
      url: `${TDT_LAYER_SERVICE_BASE_URL}/ibo_c/wmts?tk=${TDT_KEY}`,
      layer: "ibo",
      matrixSet: "c",
      format: "tiles",
      projection,
      tileGrid: _tileGrid,
      style: "default",
      wrapX: true,
    }),
    visible: visible ? mark : visible,
  });
  borderLayer.set(keys.LAYER_TYPE_KEY, "dark-vector");
  borderLayer.set(keys.LAYER_NAME_KEY, "border");
  borderLayer.set(keys.LAYER_SOURCE_KEY, "tianditu");
  borderLayer.set(keys.LAYER_FORMAT_KEY, "wmts");

  return [defaultLayer, markerLayer, borderLayer];
};
/**
 * @description: 显示天地图指定图层
 * @param {Object} options 配置项
 * @param {TDTLayerType} options.layer 显示图层类型
 * @param {boolean} options.mark 是否显示图层标注
 * @returns
 */
export const showTianDiTuLayer = (
  options: { layer?: TDTLayerType; mark?: boolean } = {}
): void => {
  const mapInstance = getMap();
  if (!mapInstance) {
    return;
  }

  const { layer: layerName = "satellite", mark = true } = options;

  // 检验暗色过滤器是否存在
  if (layerName === "dark-vector") {
    const filter = document.querySelector("filter#ol-dark-filter");
    if (!filter) {
      const el = document.createElementNS(
        "http://www.w3.org/2000/svg",
        "filter"
      );
      el.setAttribute("id", "ol-dark-filter");
      el.setAttribute("x", "-10%");
      el.setAttribute("y", "-10%");
      el.setAttribute("width", "120%");
      el.setAttribute("height", "120%");
      el.setAttribute("filterUnits", "objectBoundingBox");
      el.setAttribute("primitiveUnits", "userSpaceOnUse");
      el.setAttribute("color-interpolation-filters", "linearRGB");
      const matrix = document.createElementNS(
        "http://www.w3.org/2000/svg",
        "feColorMatrix"
      );
      matrix.setAttribute("type", "matrix");
      matrix.setAttribute(
        "values",
        [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0].join(" ")
      );
      matrix.setAttribute("in", "SourceGraphic");
      matrix.setAttribute("result", "colormatrix");
      el.appendChild(matrix);
      const transfer = document.createElementNS(
        "http://www.w3.org/2000/svg",
        "feComponentTransfer"
      );
      transfer.setAttribute("in", "colormatrix");
      transfer.setAttribute("result", "componentTransfer");
      transfer.innerHTML = [
        // eslint-disable-next-line quotes
        '<feFuncR type="table" tableValues="0.23 0.01 0" />',
        // eslint-disable-next-line quotes
        '<feFuncG type="table" tableValues="0.45 0.04 0" />',
        // eslint-disable-next-line quotes
        '<feFuncB type="table" tableValues="0.91 0.13 0" />',
        // eslint-disable-next-line quotes
        '<feFuncA type="table" tableValues="0 1" />',
      ].join("\n");
      el.appendChild(transfer);
      const blend = document.createElementNS(
        "http://www.w3.org/2000/svg",
        "feBlend"
      );
      blend.setAttribute("mode", "normal");
      blend.setAttribute("in", "componentTransfer");
      blend.setAttribute("in2", "SourceGraphic");
      blend.setAttribute("result", "blend");
      el.appendChild(blend);
      document.body.insertBefore(el, document.body.querySelector("div"));
    }
  }

  // 图层处理
  mapInstance.getAllLayers().forEach((layer: any) => {
    const layerSource = layer.get(keys.LAYER_SOURCE_KEY);
    const layerType = layer.get(keys.LAYER_TYPE_KEY);
    const _layerName = layer.get(keys.LAYER_NAME_KEY) ?? "default";
    if (layerSource !== "tianditu") {
      return;
    }
    if (layerType !== layerName) {
      layer.setVisible(false);
      return;
    }
    if (!["default"].includes(_layerName)) {
      layer.setVisible(!!mark);
    } else {
      layer.setVisible(true);
    }
  });
};
